// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace SnapObjects.Data
{
    internal class ModelTableBuilder
    {
        private readonly ModelSqlHelper _modelSqlHelper;
        private readonly SqlExpressionBuilder _sqlExpressionBuilder;
        private readonly PocoModelMeta _modelMeta;

        public ModelTableBuilder(
            ModelSqlHelper modelSqlHelper,
            SqlExpressionBuilder sqlExpressionBuilder)
        {
            _modelSqlHelper = modelSqlHelper;
            _sqlExpressionBuilder = sqlExpressionBuilder;
            _modelMeta = _modelSqlHelper.ModelMeta;
        }

        public void BuildFromAndJoin(ISqlFromBuilder sqlFromBuilder, IReadOnlyList<TableAttribute> tables)
        {
            if (tables.Count == 0)
            {
                sqlFromBuilder.From(_modelMeta.GetFullTableName(PocoModelMeta.TABLE_ID));
                return;
            }

            foreach (var table in tables)
            {
                if (table is IFromTable)
                {
                    this.BuildFrom(sqlFromBuilder, (IFromTable)table);
                }
                else if (table is IJoinTable)
                {
                    this.BuildJoin(sqlFromBuilder, (IJoinTable)table);
                }
                else
                {
                    sqlFromBuilder.From(_modelMeta.GetFullTableName(PocoModelMeta.TABLE_ID));
                }
            }
        }

        private void BuildFrom(
            ISqlFromBuilder sqlFromBuilder,
            IFromTable table)
        {
            if (table.AliasDefined)
            {
                var tableAlias = _modelSqlHelper.GetTableAliasOrName(table.Id, throwIfFail: true);

                sqlFromBuilder.From(_modelMeta.GetFullTableName(table.Id), tableAlias);
            }
            else
            {
                sqlFromBuilder.From(_modelMeta.GetFullTableName(table.Id));
            }

            if (!System.String.IsNullOrWhiteSpace(table.WhereRaw))
            {
                var expression = _sqlExpressionBuilder.BuildSqlExpression(
                        table.WhereRaw, buildSubQueris: true, buildParameters: true);

                sqlFromBuilder.WhereRaw(expression);
            }
        }

        private void BuildJoin(ISqlFromBuilder sqlFromBuilder, IJoinTable joinTable)
        {
            var alias = _modelSqlHelper.GetTableAliasOrName(joinTable.Id, throwIfFail: true);
            var fullTableName = _modelMeta.GetFullTableName(joinTable.Id);
            ISqlJoinOnBuilder onBuilder;

            if (joinTable.JoinType == SqlJoinType.Join)
            {
                onBuilder = joinTable.AliasDefined ?
                    sqlFromBuilder.Join(fullTableName, alias) : sqlFromBuilder.Join(fullTableName);
            }
            else if (joinTable.JoinType == SqlJoinType.Left)
            {
                onBuilder = joinTable.AliasDefined ?
                    sqlFromBuilder.LeftJoin(fullTableName, alias) : sqlFromBuilder.LeftJoin(fullTableName);
            }
            else if (joinTable.JoinType == SqlJoinType.Right)
            {
                onBuilder = joinTable.AliasDefined ?
                    sqlFromBuilder.RightJoin(fullTableName, alias) : sqlFromBuilder.RightJoin(fullTableName);
            }
            else if (joinTable.JoinType == SqlJoinType.Inner)
            {
                onBuilder = joinTable.AliasDefined ?
                    sqlFromBuilder.InnerJoin(fullTableName, alias) : sqlFromBuilder.InnerJoin(fullTableName);
            }
            else
            {
                onBuilder = joinTable.AliasDefined ?
                    sqlFromBuilder.FullJoin(fullTableName, alias) : sqlFromBuilder.FullJoin(fullTableName);
            }

            if (!System.String.IsNullOrWhiteSpace(joinTable.OnRaw))
            {
                var onExpression = _sqlExpressionBuilder.BuildSqlExpression(
                                        joinTable.OnRaw, buildSubQueris: true, buildParameters: true);

                onBuilder.OnRaw(onExpression);
            }
        }
    }
}
